package com.cheng.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cheng.entity.Tieba;
import com.cheng.entity.Users;
import com.cheng.service.TiebaService;
import com.cheng.service.UsersService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * Author: Cheng
 * Date: 2019/7/22
 * Time: 14:39
 * Description: 签到逻辑
 */
@Component
public class TiebaUtil {
    //    本来就用@Component注解了 本想不用static修饰变量与方法的 但是 简单呀。。
    //    静态方法中不能引用非静态方法，@Autowired注入非静态的方法后，
    //    在static方法中编译虽然不报错，但运行仍会报错，因此写工具类时候注意
    @Autowired
    private TiebaService<Tieba> tiebaService;
    @Autowired
    private UsersService usersService;
    @Autowired
    private EmailUtil emailUtil;

    private final Logger logger = LoggerFactory.getLogger(TiebaUtil.class);

    /**
     * 验证输入参数是否完整
     *
     * @param tieba
     * @return
     */
    public static boolean checkFields(Tieba tieba) {
        if (StringUtils.isBlank(tieba.getBduss()) || StringUtils.isBlank(tieba.getQq()) || StringUtils.isBlank(tieba.getTaskname()))
            return false;
        return true;
    }

    /**
     * 获取关注贴吧到数据库
     *
     * @param tieba
     * @throws Exception
     */
    public JSONArray updateForum(Tieba tieba) throws Exception {
        JSONObject forumJson = new JSONObject(true);
        JSONArray forumArray = new JSONArray();
        String bduss = tieba.getBduss();
        String tbstr = TiebaSign.verification(bduss);
        if (tbstr == null) {
            tieba.setForumList("");
            tieba.setValidity(0);
            tieba.updateById();
            return null;
        }
        String forums = TiebaSign.getForums(bduss);
        boolean flag = false;
        int totalTbs = 0;
//        循环10次 一次最多接收200个吧名，也就是说可以签到最多2000个吧 可随意扩充
        for (int i = 1; i <= 10; i++) {
            if (flag) break;
            if (i > 1)
                forums = TiebaSign.getForumsPage(i, 200, bduss);
//            bduss非192个标准字符造成检测已登录，但获取不到贴吧列表
            if (!forums.contains("forum_list")) {
                tieba.setForumList("");
                tieba.setValidity(0);
                tieba.updateById();
                return null;
            }
            JSONObject jo = (JSONObject) JSON.parse(forums);
            JSONObject forum_list = jo.getJSONObject("forum_list");
            JSONArray jsonArray = forum_list.getJSONArray("non-gconforum");
            Integer totalTb = TiebaSign.getTotalTb(forums);
            totalTbs += totalTb;
            if (totalTb < 200)
                flag = true;
            logger.info("获取列表成功>>{}", i);
            for (Object o : jsonArray) {
                JSONObject forumOne = new JSONObject(true);
                JSONObject forum = (JSONObject) JSON.toJSON(o);
                String id = forum.getString("id");
                String name = forum.getString("name");
                forumOne.put("id", id);
                forumOne.put("name", name);
                forumOne.put("status", 0);
                forumArray.add(forumOne);
            }
            if (forum_list.containsKey("gconforum")) {
                logger.info("特权贴吧获取中>>");
                JSONArray gconforum = forum_list.getJSONArray("gconforum");
                for (Object o : gconforum) {
                    JSONObject forumOne = new JSONObject(true);
                    JSONObject forum = (JSONObject) JSON.toJSON(o);
                    String id = forum.getString("id");
                    String name = forum.getString("name");
                    forumOne.put("id", id);
                    forumOne.put("name", name);
                    forumOne.put("status", 0);
                    forumArray.add(forumOne);
                }
            }
        }
        forumJson.put("size", totalTbs);
        forumJson.put("rows", forumArray);
        tieba.setForumList(forumJson.toString());
        tieba.updateById();
        return forumArray;
    }

    /*查询数据库
     * forumList是否为空->空->执行获取操作并填入
     * 遍历forumList查看状态为0的行
     * 签到为0的行->签到成功状态改为1
     * 如果签到任务出现可贴吧不存在或拉黑 标记2、3
     * 全部是1或其他状态(不包含0)后更新finishTime为今日
     * */
    public void sign(Tieba tieba) throws Exception {
        String bduss = tieba.getBduss();
//        更新访问时间与重试次数
        tieba.setRetryCount(tieba.getRetryCount() == null ? 0 : tieba.getRetryCount());
//        重试次数为0时说明当日未执行 从服务器获取贴吧列表 重试次数>0时都直接从数据库取
        if (StringUtils.isBlank(tieba.getForumList()) || tieba.getRetryCount() == 0) {
            //更新贴吧信息
            JSONArray tf = updateForum(tieba);
            if (tf == null) {
                errorSend(tieba);
                return;
            }
        }
//        对登录信息进行校验
        String tbstr = TiebaSign.verification(bduss);
        if (tbstr == null) {
            tieba.setValidity(0);
            errorSend(tieba);
            logger.error("登录验证失败,更新字段:{}", tieba.updateById());
            return;
        }
        tieba.setRetryCount(tieba.getRetryCount() + 1);
        tieba.setVisitTime(DateUtil.getDate());
        tieba.updateById();
        tieba = tiebaService.selectById(tieba.getId());
        JSONObject jo = (JSONObject) JSON.parse(tieba.getForumList());
        JSONArray rows = jo.getJSONArray("rows");
        List<Map<String, Object>> rowsList = JSONArray.parseObject(rows.toString(), List.class);
        int point = 0;
        JSONObject forumJson = new JSONObject(true);
        forumJson.put("size", rows.size());
        for (Map<String, Object> forum : rowsList) {
            if ("1".equals(forum.get("status")) || "2".equals(forum.get("status")) || "3".equals(forum.get("status")) || "4".equals(forum.get("status"))) {
                logger.info("跳过：{}", forum.get("name"));
                continue;
            }
            String id = (String) forum.get("id");
            String name = (String) forum.get("name");
            logger.info("正在签到{}：", name);
            String signResult = TiebaSign.signForums(name, id, tbstr, bduss);
            JSONObject result = (JSONObject) JSON.parse(signResult);
            if (signResult.contains("error_code") && signResult.contains("error_msg")) {
                String error_msg = result.getString("error_msg");
                logger.info("fail: {}", error_msg);
                if (error_msg.contains("目录出问题")) {
                    forum.put("status", "2");
                } else if (error_msg.contains("已经签过")) {
                    forum.put("status", "1");
                } else if (error_msg.contains("黑名单中")) {
                    forum.put("status", "3");
                } else if (error_msg.contains("已被封禁")) {
                    forum.put("status", "5");
                } else if (error_msg.contains("加载数据失败")) {
//                    由于我设置当状态为0时候我才会执行签到 因此当重试次数大于2次才改成错误代码4
//                    否则状态为0 重试2次签到 再改成4 报错信息加载失败可能是被拉黑 或已改名 或其他未知原因
                    if (tieba.getRetryCount() > 2) {
                        forum.put("status", "4");
                    } else {
                        forum.put("status", "0");
                    }
                } else {
                    if (tieba.getRetryCount() > 2) {
                        forum.put("status", "6");
                    } else {
                        forum.put("status", "0");
                    }
                }
                continue;
            }
            forum.put("status", "1");
            JSONObject user_info = result.getJSONObject("user_info");
            point += Integer.valueOf(user_info.getString("sign_bonus_point"));
            logger.info("签到成功!经验+{},今天第{}个签到", user_info.getString("sign_bonus_point"), user_info.getString("user_sign_rank"));
        }
        forumJson.put("rows", rowsList);
        tieba.setAmount(selectRows(forumJson.getJSONArray("rows"), "1").size() + "/" + rows.size());
        tieba.setPoints(point);
        tieba.setVisitCount(tieba.getVisitCount() + 1);
        tieba.setForumList(forumJson.toString());
//        签到完成 重置重试次数为0
        if (!rowsList.toString().contains("\"0\"")) {
            tieba.setFinishTime(DateUtil.getDate());
            tieba.setRetryCount(0);
        }
        tieba.updateById();
    }

    private void errorSend(Tieba tieba1) {
        try {
            Users user = usersService.selectById(tieba1.getQq());
            if (user.getEmailStatus() == 1) {
                emailUtil.simpleSend(user.getEmail(), "您的签到任务bduss已过期！请及时更新", "您的签到任务：" + tieba1.getTaskname() +
                        " 的bduss已过期，请及时更新！您也可以访问以下链接进入管理页面：http://hik.win/admin/tieba.html?qq=" + user.getQq());
            }
        } catch (Exception e) {
            logger.info("查询用户邮箱信息不存在");
        }

    }

    /**
     * 关于状态status
     * 0.未签到
     * 1.已签到
     * 2.目录出问题
     * 3.黑名单中
     * 4.加载数据失败
     * 5.已被封禁
     * 6.未知错误
     *
     * @param rows
     * @param stat
     * @return
     */
    public static JSONArray selectRows(JSONArray rows, String stat) {
        JSONArray jsonArray = new JSONArray();
        for (Object row : rows) {
            JSONObject o = (JSONObject) JSON.toJSON(row);
            String status = o.getString("status");
            if (stat.equals(status)) {
                jsonArray.add(o.getString("name"));
            }
        }
        return jsonArray;
    }

    /**
     * 旧签到方式
     * 即时获取不将贴吧信息存数据库
     * @param tieba
     * @return
     * @throws Exception
     */
/*    public MsgRespose tbsSign(Tieba tieba) throws Exception {
        MsgRespose msgRespose = new MsgRespose();
        String bduss = tieba.getBduss();
        cm.setMaxTotal(200);             //    设置最大连接数
        cm.setDefaultMaxPerRoute(10);    //    设置每个主机的并发数
        String tbstr = tiebaSign.verification(bduss);
        if (tbstr == null) {
            tieba.setValidity(0);
            System.out.println("验证失败更新字段:" + tiebaService.update(tieba, Condition.create().eq("bduss", bduss)));
            return msgRespose.setCode(1001).setMsg("bduss验证不通过!");
        }
        JSONObject jo = (JSONObject) JSON.parse(tiebaSign.getForums(bduss, cm));
        JSONObject forum_list = jo.getJSONObject("forum_list");
        JSONArray jsonArray = forum_list.getJSONArray("non-gconforum");
        System.out.println("获取列表成功>>>>>");
        int count = 0;
        int point = 0;
        JSONArray forumArray = new JSONArray();
        for (Object o : jsonArray) {
            JSONObject forum = (JSONObject) JSON.toJSON(o);
            String id = forum.getString("id");
            String name = forum.getString("name");
            System.out.println("正在签到" + name + "：");
            String signResult = tiebaSign.signForums(name, id, tbstr, bduss, cm);
            JSONObject result = (JSONObject) JSON.parse(signResult);
            if (signResult.contains("error_code") && signResult.contains("error_msg")) {
                System.out.println(result.getString("error_msg"));
                continue;
            }
            JSONObject user_info = result.getJSONObject("user_info");
            point += Integer.valueOf(user_info.getString("sign_bonus_point"));
            System.out.println("签到成功!经验+" + user_info.getString("sign_bonus_point") + ",今天第" + user_info.getString("user_sign_rank") + "个签到");
            count++;
        }
        tieba.setAmount(count+"/"+forumArray.size());
        tieba.setPoints(point);
        tieba.setVisitTime(new Date());
        System.out.println("======" + tieba);
        tieba.setVisitCount(tieba.getVisitCount() + 1);
        tieba.updateById();
        return msgRespose.setCode(1000).setMsg("今日共签到成功" + count + "个贴吧");
    }*/

}
